use chrono::{Datelike, Days, Months, NaiveDate, NaiveDateTime, NaiveTime};

pub fn month_of_first_day(date: NaiveDate) -> Option<NaiveDate> {
    let y = date.year();
    let m = date.month();
    NaiveDate::from_ymd_opt(y, m, 1)
}
pub fn month_of_last_day(date: NaiveDate) -> Option<NaiveDate> {
    date.checked_add_months(Months::new(1)).map(|d| {
        month_of_first_day(d)
            .map(|d| d.checked_sub_days(Days::new(1)).unwrap_or_default())
            .unwrap_or_default()
    })
}
pub fn date_part_quarter(date: NaiveDate) -> u8 {
    let m = date.month();
    let q = match m {
        1..=3 => 1u8,
        4..=6 => 2,
        7..=9 => 3,
        _ => 4,
    };
    q
}
pub fn quarter_of_first_day(date: NaiveDate) -> Option<NaiveDate> {
    let y = date.year();
    let m = date.month();
    let m2 = match m {
        1..=3 => 1u32,
        4..=6 => 4,
        7..=9 => 7,
        _ => 10,
    };
    NaiveDate::from_ymd_opt(y, m2, 1)
}
pub fn quarter_of_last_day(date: NaiveDate) -> Option<NaiveDate> {
    let mut y = date.year();
    let m = date.month();
    let m2 = match m {
        1..=3 => 4u32,
        4..=6 => 7,
        7..=9 => 10,
        _ => {
            y+=1;
            1
        },
    };
    NaiveDate::from_ymd_opt(y, m2, 1).map(|d|d.checked_sub_days(Days::new(1))).unwrap_or_default()
}
pub fn year_of_first_day(date: NaiveDate) -> Option<NaiveDate> {
    let y = date.year();
    NaiveDate::from_ymd_opt(y, 1, 1)
}
pub fn year_of_last_day(date: NaiveDate) -> Option<NaiveDate> {
    let y = date.year();
    NaiveDate::from_ymd_opt(y, 12, 31)
}

const EXCEL_EPOCH_1900: chrono::NaiveDate = chrono::NaiveDate::from_ymd_opt(1899, 12, 30).unwrap();
pub fn excel_float_to_datetime(value: f64, is_1904_system: bool) -> Option<NaiveDateTime> {
    let (epoch, needs_adjustment) = if is_1904_system {
        (NaiveDate::from_ymd_opt(1904, 1, 1).unwrap(), false)
    } else {
        (EXCEL_EPOCH_1900, value >= 60.0)
    };

    let adjusted_days = if needs_adjustment { value - 1.0 } else { value };

    let days = adjusted_days.trunc() as i64;
    let seconds = (adjusted_days.fract() * 86400.0).round() as u32;

    epoch
        .checked_add_signed(chrono::Duration::days(days))
        .and_then(|date| {
            chrono::NaiveTime::from_num_seconds_from_midnight_opt(seconds, 0)
                .map(|time| NaiveDateTime::new(date, time))
        })
}

/// 解析 ISO 8601 持续时间格式为秒数
/// 例如：
/// - PT1H30M -> 5400秒 (1小时30分钟)
/// - P1DT2H3M4S -> 93784秒 (1天2小时3分钟4秒)
pub fn parse_iso8601_duration(duration: &str) -> anyhow::Result<i64> {
    // 基本验证
    if !duration.starts_with('P') {
        return Err(anyhow::anyhow!(
            "Invalid ISO 8601 duration format: {}",
            duration
        ));
    }
    let mut total_seconds = 0_i64;
    let mut number = String::new();
    let mut has_time = false;
    for c in duration.chars() {
        match c {
            'P' => continue, // 开始标记
            'T' => {
                has_time = true;
                continue;
            }
            'Y' => {
                if let Ok(years) = number.parse::<i64>() {
                    // 粗略计算：1年 = 365天
                    total_seconds += years * 365 * 24 * 3600;
                }
                number.clear();
            }
            'M' => {
                if let Ok(value) = number.parse::<i64>() {
                    if has_time {
                        // 分钟
                        total_seconds += value * 60;
                    } else {
                        // 月份 (粗略计算：1月 = 30天)
                        total_seconds += value * 30 * 24 * 3600;
                    }
                }
                number.clear();
            }
            'W' => {
                if let Ok(weeks) = number.parse::<i64>() {
                    total_seconds += weeks * 7 * 24 * 3600;
                }
                number.clear();
            }
            'D' => {
                if let Ok(days) = number.parse::<i64>() {
                    total_seconds += days * 24 * 3600;
                }
                number.clear();
            }
            'H' => {
                if let Ok(hours) = number.parse::<i64>() {
                    total_seconds += hours * 3600;
                }
                number.clear();
            }
            'S' => {
                if let Ok(seconds) = number.parse::<i64>() {
                    total_seconds += seconds;
                }
                number.clear();
            }
            c if c.is_ascii_digit() || c == '.' => {
                number.push(c);
            }
            _ => {
                return Err(anyhow::anyhow!("Unexpected character in duration: {}", c));
            }
        }
    }
    Ok(total_seconds)
}

pub fn get_date_1970()->NaiveDate {
    let nd = NaiveDate::from_ymd_opt(1900, 1, 1).unwrap();
    nd
}

pub fn get_date_time_1900()->NaiveDateTime {
    let nd = NaiveDate::from_ymd_opt(1900, 1, 1).unwrap();
    let ndt = NaiveDateTime::new(nd, NaiveTime::from_hms_opt(0, 0, 0).unwrap());
    ndt
}
pub fn get_date_time_1970()->NaiveDateTime {
    let nd = NaiveDate::from_ymd_opt(1970, 1, 1).unwrap();
    let ndt = NaiveDateTime::new(nd, NaiveTime::from_hms_opt(0, 0, 0).unwrap());
    ndt
}